package Thread;

/**
 * 概念：
 *    java的内存模型：java的内存（JMM）:我们常说的JVM内存模式指的是JVM的内存分区，Java虚拟机规范中定义了Java内存模型（Java Memory Model，JMM），用于屏蔽掉各种硬件和操作系统的内存访问差异，
 *    以实现让Java程序在各种平台下都能达到一致的并发效果，JMM规范了Java虚拟机与计算机内存是如何协同工作的：规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值，以及在必须时如何同步的访问共享变量。
 *    Java内存模型（不仅仅是JVM内存分区）：调用栈和本地变量存放在线程栈上，对象存放在堆上。
 *
 *
 *    缓存一致性问题：
 *         在多处理器系统中，每个处理器都有自己的高速缓存，而它们又共享同一主内存（MainMemory）。基于高速缓存的存储交互很好地解决了处理器与内存的速度矛盾，
 *    但是也引入了新的问题：缓存一致性（CacheCoherence）。当多个处理器的运算任务都涉及同一块主内存区域时，将可能导致各自的缓存数据不一致的情况，
 *    如果真的发生这种情况，那同步回到主内存时以谁的缓存数据为准呢？为了解决一致性的问题，需要各个处理器访问缓存时都遵循一些协议，在读写时要根据协议来进行操作
 *
 *    内存可见性问题：各个线程对主内存共享变量的操作都是各个线程拷贝自己的工作内存进行操作后再写会主内存中
 *                   这就存在一个线程AA修改了共享变量X的值，但是未写回主内存时候，另外一个线程BBB又读取了主内存数据，对同一个共享变量X进行的操作，此时线程A对线程B是不可见的
 *                   这种工作内存和主内存的同步延迟现象就造成了可见性问题
 *
 *    指令重排序问题：
 *         为了使得处理器内部的运算单元能尽量被充分利用，处理器可能会对输入代码进行乱序执行（Out-Of-Order Execution）优化，处理器会在计算之后将乱序执行的结果重组，保证该结果与顺序执行的结果是一致的，但并不保证程序中各个语句计算的先后顺序与输入代码中的顺序一致。
 *    因此，如果存在一个计算任务依赖另一个计算任务的中间结果，那么其顺序性并不能靠代码的先后顺序来保证。与处理器的乱序执行优化类似，Java虚拟机的即时编译器中也有类似的指令重排序（Instruction Reorder）优化
 */
public class Volatile_study {

    /**
     *  共享变量加
     */
   volatile int i=0;

    public void add50(){
        i=50;
    }

    public synchronized void addplusplus(){
        i++;
    }

    public static void main(String[] args) {
        lockOperation();
        System.out.println("--------------------------------------------");


       // seeOkeyByVolatile();


    }

    /**
     * 如果addplusplus（）不是一个原子操作，那么计算的数量将不准确， i++ 不是原子操作
     */
    private static void lockOperation() {
        Volatile_study  vs=new Volatile_study();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {

                for (int j = 0; j < 1000; j++) {
                    vs.addplusplus();
                }
            },i+" 线程").start();
        }


        //需要上面20个线程全部计算结束后，再用main计算总数
        while (Thread.activeCount()>2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"\t  finished  i="+vs.i);
    }

    //volatile可以保存内存可见性，及时通知其他线程，主物理内存已经修改
    private static void seeOkeyByVolatile() {
        Volatile_study  vs=new Volatile_study();
        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"\t come in");
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            vs.add50();
            System.out.println(Thread.currentThread().getName()+"\t updated");
        },"threadA");


        thread.start();

        while (vs.i==0){

        }
        System.out.println(Thread.currentThread().getName()+"\t  mission is over");
    }


}
